package cn.ug.pay.service.impl;

import cn.ug.aop.RemoveCache;
import cn.ug.aop.SaveCache;
import cn.ug.bean.base.DataTable;
import cn.ug.bean.base.SerializeObject;
import cn.ug.bean.status.DeleteStatus;
import cn.ug.bean.type.ResultType;
import cn.ug.config.CacheUtilsService;
import cn.ug.config.FundRateConfig;
import cn.ug.config.RedisGlobalLock;
import cn.ug.core.ensure.Ensure;
import cn.ug.enums.RateKeyEnum;
import cn.ug.enums.WxTemplateEnum;
import cn.ug.feign.PriceService;
import cn.ug.feign.ProductService;
import cn.ug.feign.RateSettingsService;
import cn.ug.mq.DelayMessagePostProcessor;
import cn.ug.msg.bean.status.CommonConstants;
import cn.ug.msg.mq.Msg;
import cn.ug.msg.mq.WxMessageParamBean;
import cn.ug.msg.mq.WxNotifyData;
import cn.ug.pay.bean.*;
import cn.ug.pay.bean.type.BillGoldTradeType;
import cn.ug.pay.bean.type.BillGoldType;
import cn.ug.pay.mapper.BillMapper;
import cn.ug.pay.mapper.MemberGoldMapper;
import cn.ug.pay.mapper.PayTbillMapper;
import cn.ug.pay.mapper.PayTbillStatisticsMapper;
import cn.ug.pay.mapper.entity.MemberGold;
import cn.ug.pay.mapper.entity.PayGoldStock;
import cn.ug.pay.mapper.entity.PayTbillStatistics;
import cn.ug.pay.service.BillGoldService;
import cn.ug.pay.service.GoldRecordService;
import cn.ug.pay.service.MemberAccountService;
import cn.ug.pay.service.MemberGoldService;
import cn.ug.service.impl.BaseServiceImpl;
import cn.ug.util.BigDecimalUtil;
import cn.ug.util.UF;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.apache.commons.lang3.StringUtils;
import org.dozer.DozerBeanMapper;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

import static cn.ug.config.CacheType.OBJECT;
import static cn.ug.config.CacheType.SEARCH;
import static cn.ug.config.QueueName.QUEUE_DELAY_PER_MESSAGE_TTL_MSG_WX_SEND;
import static cn.ug.config.QueueName.QUEUE_MSG_SEND;
import static java.math.BigDecimal.ROUND_HALF_UP;

/**
 * @author kaiwotech
 */
@Service
public class MemberGoldServiceImpl extends BaseServiceImpl implements MemberGoldService {

    /** 卖金临时锁定金价 */
	private static final String KEY_SELL_GOLD_PRICE = "key:sell:gold:price:";
    @Autowired
	private RateSettingsService rateSettingsService;
    @Resource
    private AmqpTemplate amqpTemplate;
    @Resource
	private MemberGoldMapper memberGoldMapper;
    @Resource
	private GoldRecordService goldRecordService;
    @Resource
    private MemberAccountService memberAccountService;
    @Resource
	private BillGoldService billGoldService;
    @Resource
	private PriceService priceService;
    @Resource
	private RedisGlobalLock redisGlobalLock;
    @Resource
	private CacheUtilsService cacheUtilsService;
    @Resource
	private FundRateConfig fundRateConfig;
    @Resource
	private DozerBeanMapper dozerBeanMapper;
	@Resource
	private ProductService productService;
	@Autowired
	private BillMapper billMapper;
	@Autowired
	private PayTbillStatisticsMapper payTbillStatisticsMapper;

	//每日最高可卖克重
	private static final String SELL_MAX_GRAM_PERDAY = "sellMaxGramPerDay";

	@Override
	@RemoveCache(cleanSearch = true)
	@Transactional(rollbackFor = Exception.class)
	public int save(MemberGoldBean entityBean) {
		// 数据完整性校验
		if(null == entityBean || StringUtils.isBlank(entityBean.getMemberId())) {
			Ensure.that(true).isTrue("00000002");
		}
		MemberGold entity = dozerBeanMapper.map(entityBean, MemberGold.class);
		if(StringUtils.isBlank(entity.getId())) {
			entity.setId(UF.getRandomUUID());
		}
		int rows = memberGoldMapper.insert(entity);
		Ensure.that(rows).isLt(1,"00000005");
        return 0;
	}

	@Override
	@RemoveCache(cleanSearch = true, cleanObjectByKeyPosition = 0)
	public int delete(String id) {
		if(StringUtils.isBlank(id)) {
			return 0;
		}

		return memberGoldMapper.delete(id);
	}

	@Override
	@RemoveCache(cleanSearch = true, cleanObjectByKeyPosition = 0)
	public int deleteByIds(String[] id){
		if(id == null || id.length<=0){
			return 0;
		}

		return memberGoldMapper.deleteByIds(id);
	}

	@Override
	@RemoveCache(cleanSearch = true, cleanObjectByKeyPosition = 0)
	public int removeByIds(String[] id) {
		if(id == null || id.length<=0){
			return 0;
		}

		return memberGoldMapper.updateByPrimaryKeySelective(
				getParams()
						.put("id", id)
						.put("deleted", DeleteStatus.YES)
						.toMap()
		);
	}

	@Override
	@SaveCache(cacheType = OBJECT)
	public MemberGoldBean findById(String id) {
		if(StringUtils.isBlank(id)) {
			return null;
		}

		MemberGold entity = memberGoldMapper.findById(id);
		if(null == entity) {
			return null;
		}

		MemberGoldBean entityBean = dozerBeanMapper.map(entity, MemberGoldBean.class);
		entityBean.setAddTimeString(UF.getFormatDateTime(entity.getAddTime()));
		entityBean.setModifyTimeString(UF.getFormatDateTime(entity.getModifyTime()));
		return entityBean;
	}

	@Override
	public MemberGoldBean findByMemberId(String memberId) {
		/*List<MemberGoldBean> list = query(null, null, null, null,
				null, null, null, null,
				null, null, null, null,
				null, null, memberId, null, null, null);
		if(null == list || list.isEmpty()) {
			return null;
		}

		return list.get(0);*/
		if (StringUtils.isNotBlank(memberId)) {
			MemberGold memberGold = memberGoldMapper.findByMemberId(memberId);
			if (memberGold == null) {
				return null;
			}
			MemberGoldBean bean = dozerBeanMapper.map(memberGold, MemberGoldBean.class);
			bean.setAddTimeString(UF.getFormatDateTime(memberGold.getAddTime()));
			bean.setModifyTimeString(UF.getFormatDateTime(memberGold.getModifyTime()));
			return bean;
		}
		return null;
	}

	@Override
	@SaveCache(cacheType = SEARCH)
	public DataTable<MemberGoldBean> query(String order, String sort, int pageNum, int pageSize,
										   BigDecimal amountMin, BigDecimal amountMax,
										   BigDecimal usableAmountMin, BigDecimal usableAmountMax,
										   BigDecimal freezeAmountMin, BigDecimal freezeAmountMax,
										   BigDecimal turnIntoAmountMin, BigDecimal turnIntoAmountMax,
										   BigDecimal turnOutAmountMin, BigDecimal turnOutAmountMax,
										   LocalDateTime addTimeMin, LocalDateTime addTimeMax,
										   String memberName, String memberMobile, String keyword) {
		Page<MemberGoldBean> page = PageHelper.startPage(pageNum, pageSize);
		List<MemberGoldBean> list = query(order, sort, amountMin, amountMax,
				usableAmountMin, usableAmountMax,
				freezeAmountMin, freezeAmountMax,
				turnIntoAmountMin, turnIntoAmountMax,
				turnOutAmountMin, turnOutAmountMax,
				addTimeMin, addTimeMax,
				null, memberName, memberMobile, keyword);
		return new DataTable<>(page.getPageNum(), page.getPageSize(), page.getTotal(), list);
	}

	@Override
	public DataTable<MemberGoldBean> queryActiveAccount(int pageNum, int pageSize) {
		Page<MemberGoldBean> page = PageHelper.startPage(pageNum, pageSize);
		List<MemberGoldBean> list = queryActiveAccount();
		return new DataTable<>(page.getPageNum(), page.getPageSize(), page.getTotal(), list);
	}

	@Override
	public List<MemberGoldBean> queryActiveAccountForList(int offset, int size) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("offset", offset);
		params.put("size", size);
		List<MemberGoldBean> dataList = new ArrayList<>();
		List<MemberGold> list = memberGoldMapper.queryActiveAccountForList(params);
		for (MemberGold o : list) {
			MemberGoldBean objBean = dozerBeanMapper.map(o, MemberGoldBean.class);
			objBean.setAddTimeString(UF.getFormatDateTime(o.getAddTime()));
			objBean.setModifyTimeString(UF.getFormatDateTime(o.getModifyTime()));
			dataList.add(objBean);
		}
		return dataList;
	}

	@Override
	public List<MemberGoldBean> queryActiveAccountForCurrentList(int offset, int size) {
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("offset", offset);
		params.put("size", size);
		List<MemberGoldBean> dataList = new ArrayList<>();
		List<MemberGold> list = memberGoldMapper.queryActiveAccountForCurrentList(params);
		for (MemberGold o : list) {
			MemberGoldBean objBean = dozerBeanMapper.map(o, MemberGoldBean.class);
			objBean.setAddTimeString(UF.getFormatDateTime(o.getAddTime()));
			objBean.setModifyTimeString(UF.getFormatDateTime(o.getModifyTime()));
			dataList.add(objBean);
		}
		return dataList;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	@RemoveCache(cleanAll = true, cleanService = {GoldRecordServiceImpl.class, MemberGoldServiceImpl.class})
	public void interestCalculate(String memberId) {
		if (StringUtils.isBlank(memberId)) {
			return;
		}
		MemberGoldBean memberGoldBean = findByMemberId(memberId);
		if (null == memberGoldBean || StringUtils.isBlank(memberGoldBean.getMemberId())) {
			error("找不到会员，memberId = " + memberId);
			return;
		}

		// 1、发放利息 ================================================================
		// T日利息
		BigDecimal interestNowAmount = memberGoldBean.getInterestNowAmount();
		BigDecimal interest = interestNowAmount;
		// (T-1日利息) += T日利息
		memberGoldBean.setInterestHistoryAmount(BigDecimalUtil.add(memberGoldBean.getInterestHistoryAmount(), interestNowAmount));
		// (T-1日累计利息) += T日利息
		memberGoldBean.setInterestHistoryTotalAmount(BigDecimalUtil.add(memberGoldBean.getInterestHistoryTotalAmount(), interestNowAmount));
		// 清零T日利息
		memberGoldBean.setInterestNowAmount(BigDecimal.ZERO);

		// 2、计算T-1日本金 ===========================================================
		// T日本金
		BigDecimal principalNowAmount = memberGoldBean.getPrincipalNowAmount();
		// (T-1日本金) += T日本金
		memberGoldBean.setPrincipalHistoryAmount(BigDecimalUtil.add(memberGoldBean.getPrincipalHistoryAmount(), principalNowAmount));
		// (T-1日累计本金) += T日本金
		memberGoldBean.setPrincipalHistoryTotalAmount(BigDecimalUtil.add(memberGoldBean.getPrincipalHistoryTotalAmount(), principalNowAmount));
		// 清零T日本金
		memberGoldBean.setPrincipalNowAmount(BigDecimal.ZERO);
		// 本金 = T日本金 + (T-1日本金)
		memberGoldBean.setPrincipalAmount(BigDecimalUtil.adds(memberGoldBean.getPrincipalNowAmount(), memberGoldBean.getPrincipalHistoryAmount()));

		// 3、计算T日利息（第二天到账） =================================================
		// 活期年化收益利率
		BigDecimal income = fundRateConfig.getCurrentGoldAnnualIncome();
		// T日利息 = T-1日本金 * 年化收益 / 100 / 365
		interestNowAmount = memberGoldBean.getPrincipalHistoryAmount();
		interestNowAmount = interestNowAmount.multiply(income);
		interestNowAmount = interestNowAmount.divide(new BigDecimal("100"), 10, ROUND_HALF_UP);
		interestNowAmount = interestNowAmount.divide(new BigDecimal("365"), 10, ROUND_HALF_UP);
		memberGoldBean.setInterestNowAmount(BigDecimalUtil.to5Point(interestNowAmount));
		// 活期利息 = T日利息 + (T-1日利息)
		//memberGoldBean.setInterestAmount(BigDecimalUtil.adds(memberGoldBean.getInterestNowAmount(), memberGoldBean.getInterestHistoryAmount()));
		// 活期利息 = (T-1日利息)  2018-03-30决定活期利息不包含T日利息。T日利息对用户不可见
		memberGoldBean.setInterestAmount(memberGoldBean.getInterestHistoryAmount());
		// 可用资产 = 本金 + 活期利息
		memberGoldBean.setUsableAmount(BigDecimalUtil.adds(memberGoldBean.getPrincipalAmount(), memberGoldBean.getInterestAmount()));
		// 总资产 = 可用资产 + 冻结资产
		memberGoldBean.setTotalAmount(BigDecimalUtil.adds(memberGoldBean.getUsableAmount(), memberGoldBean.getFreezeAmount()));

		// 4、修改【资产总表】 ========================================================
		String[] ids = {memberGoldBean.getId()};
		int rows = memberGoldMapper.updateByPrimaryKeySelective(
				getParams()
						.put("id", ids)
						.put("totalAmount", memberGoldBean.getTotalAmount())
						.put("usableAmount", memberGoldBean.getUsableAmount())
						.put("principalAmount", memberGoldBean.getPrincipalAmount())
						.put("principalNowAmount", memberGoldBean.getPrincipalNowAmount())
						.put("principalHistoryAmount", memberGoldBean.getPrincipalHistoryAmount())
						.put("principalHistoryTotalAmount", memberGoldBean.getPrincipalHistoryTotalAmount())
						.put("interestAmount", memberGoldBean.getInterestAmount())
						.put("interestNowAmount", memberGoldBean.getInterestNowAmount())
						.put("interestHistoryAmount", memberGoldBean.getInterestHistoryAmount())
						.put("interestHistoryTotalAmount", memberGoldBean.getInterestHistoryTotalAmount())
						.toMap());
		Ensure.that(rows).isLt(1, "17000702");

		/**
		 * 微信服务号消息推送  账户收益通知
		 */
		getLog().info(JSON.toJSONString(memberGoldBean) + "-------");
		if (interestNowAmount.compareTo(BigDecimal.ZERO) == 1) {
			WxMessageParamBean wxMessageParamBean = new WxMessageParamBean();
			wxMessageParamBean.setMemberId(memberId);
			//消息推送类型
			wxMessageParamBean.setType(WxTemplateEnum.ACCOUNT_EARNINGS.getType());
			WxTemplateEnum wxTemplateEnum = WxTemplateEnum.getWxTemplateByCode(WxTemplateEnum.ACCOUNT_EARNINGS.getType());
			WxNotifyData wxNotifyData = new WxNotifyData();

			Map<String, WxNotifyData.TemplateDataAttr> wxParamMap = new HashMap();
			WxNotifyData.TemplateDataAttr first = new WxNotifyData.TemplateDataAttr();
			first.setDataValue(wxTemplateEnum.getFirstData());
			wxParamMap.put("first", first);

			WxNotifyData.TemplateDataAttr keyword1 = new WxNotifyData.TemplateDataAttr();
			keyword1.setDataValue(interest.toString());
			wxParamMap.put("keyword1", keyword1);

			WxNotifyData.TemplateDataAttr keyword2 = new WxNotifyData.TemplateDataAttr();
			keyword2.setDataValue(memberGoldBean.getInterestHistoryTotalAmount().toString());
			wxParamMap.put("keyword2", keyword2);

			WxNotifyData.TemplateDataAttr keyword3 = new WxNotifyData.TemplateDataAttr();
			keyword3.setDataValue(memberGoldBean.getTotalAmount().toString());
			wxParamMap.put("keyword3", keyword3);

			WxNotifyData.TemplateDataAttr remark = new WxNotifyData.TemplateDataAttr();
			remark.setDataValue(wxTemplateEnum.getRemark());
			wxParamMap.put("remark", remark);

			wxNotifyData.setData(wxParamMap);
			wxMessageParamBean.setTemplateData(wxNotifyData);
			amqpTemplate.convertAndSend(QUEUE_DELAY_PER_MESSAGE_TTL_MSG_WX_SEND, wxMessageParamBean, new DelayMessagePostProcessor(8 * 60 * 60 * 1000));

		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void recordGoldDetailPerDay (String memberId){
		if (StringUtils.isBlank(memberId)) {
			return;
		}
		//MemberGoldBean memberGoldBean = findByMemberId(memberId);
		PayTbillStatistics statistics = payTbillStatisticsMapper.selectByMemberId(memberId);
		if (null == statistics || StringUtils.isBlank(statistics.getMemberId())) {
			error("找不到会员，memberId = " + memberId);
			return;
		}

		// 4、新增【可用资产详表】记录 =================================================
		GoldRecordBean goldRecordBean = new GoldRecordBean();
		goldRecordBean.setMemberId(statistics.getMemberId());
		goldRecordBean.setPrincipalNowAmount(new BigDecimal(statistics.getLeasebackGram()));
		goldRecordBean.setPrincipalHistoryAmount(new BigDecimal(statistics.getPendingGram()));
		goldRecordBean.setPrincipalHistoryTotalAmount(new BigDecimal(statistics.getLeasebackGram()+statistics.getPendingGram()+statistics.getFrozenGram()));
		goldRecordBean.setInterestNowAmount(statistics.getLeasebackIncomeAmount());
		goldRecordBean.setInterestHistoryAmount(statistics.getLeasebackIncomeGram());
		goldRecordBean.setInterestHistoryTotalAmount(new BigDecimal(statistics.getLeasebackIncomeBeans()));

		int res = goldRecordService.save(goldRecordBean);
		Ensure.that(res != 0).isTrue("17000701");

	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	@RemoveCache(cleanAll = true)
	public void addPrincipalNowAmount (String memberId, BigDecimal amount, BillGoldTradeType tradeType, BigDecimal
	goldPrice){
		info("addPrincipalNowAmount memberId = [" + memberId + "], amount = [" + amount + "], tradeType = [" + tradeType + "], goldPrice = [" + goldPrice + "]");
		if (StringUtils.isBlank(memberId) || BigDecimalUtil.isZeroOrNull(amount) || amount.compareTo(BigDecimal.ZERO) <= 0) {
			Ensure.that(true).isTrue("00000002");
		}
		MemberGoldBean memberGoldBean = findByMemberId(memberId);
		if (null == memberGoldBean || StringUtils.isBlank(memberGoldBean.getMemberId())) {
			error("找不到会员，memberId = " + memberId);
			return;
		}

		// 1、获取分布式锁，防止重复支付 ====================================================
		String key = "MemberGoldServiceImpl:addPrincipalNowAmount:" + memberId;

		if (!redisGlobalLock.tryLock(key)) {
			return;
		}
		try {
			// 1、计算T日本金 ===========================================================
			// T日本金 += 购买克重
			memberGoldBean.setPrincipalNowAmount(BigDecimalUtil.add(memberGoldBean.getPrincipalNowAmount(), amount));
			// 本金 = T日本金 + (T-1日本金)
			memberGoldBean.setPrincipalAmount(BigDecimalUtil.adds(memberGoldBean.getPrincipalNowAmount(), memberGoldBean.getPrincipalHistoryAmount()));
			// 可用资产 = 本金 + 活期利息
			memberGoldBean.setUsableAmount(BigDecimalUtil.adds(memberGoldBean.getPrincipalAmount(), memberGoldBean.getInterestAmount()));
			// 总资产 = 可用资产 + 冻结资产
			memberGoldBean.setTotalAmount(BigDecimalUtil.adds(memberGoldBean.getUsableAmount(), memberGoldBean.getFreezeAmount()));

			// 2、计算转入总资产 =============================================================
			// 转入总资产 += 转入资产
			memberGoldBean.setTurnIntoAmount(BigDecimalUtil.add(memberGoldBean.getTurnIntoAmount(), amount));

			// 3、修改【资产总表】 ========================================================
			String[] ids = {memberGoldBean.getId()};
			int rows = memberGoldMapper.updateByPrimaryKeySelective(
					getParams()
							.put("id", ids)
							.put("principalNowAmount", memberGoldBean.getPrincipalNowAmount())
							.put("principalAmount", memberGoldBean.getPrincipalAmount())
							.put("usableAmount", memberGoldBean.getUsableAmount())
							.put("totalAmount", memberGoldBean.getTotalAmount())
							.put("turnIntoAmount", memberGoldBean.getTurnIntoAmount())
							.toMap());
			Ensure.that(rows).isLt(1, "17000702");

			// 增加资产转入转出记录
			BillGoldBean billGoldBean = new BillGoldBean();
			billGoldBean.setMemberId(memberId);
			// 转入资产
			billGoldBean.setAmount(amount);
			// 手续费
			billGoldBean.setFee(BigDecimal.ZERO);
			// 实际资产(资产-手续费)
			billGoldBean.setActualAmount(BigDecimalUtil.subtract(billGoldBean.getAmount(), billGoldBean.getFee()));
			// 金价
			billGoldBean.setGoldPrice(goldPrice);
			billGoldBean.setType(BillGoldType.INCOME.getValue());
			billGoldBean.setTradeType(tradeType.getValue());
			billGoldService.save(billGoldBean);
			info("新增资产转入记录");
		} catch (Exception e) {
			error(e);
			throw e;
		} finally {
			redisGlobalLock.unlock(key);
		}
	}

	@Override
	@RemoveCache(cleanAll = true)
	public void freezeAmount (String memberId, BigDecimal amount, BigDecimal incomeAmount){
		info("freezeAmount memberId = [" + memberId + "], amount = [" + amount + "], incomeAmount = [" + incomeAmount + "]");
		if (StringUtils.isBlank(memberId)) {
			return;
		}
		if (BigDecimalUtil.isZeroOrNull(amount) || BigDecimalUtil.isZeroOrNull(incomeAmount) ||
				amount.compareTo(BigDecimal.ZERO) <= 0 || incomeAmount.compareTo(BigDecimal.ZERO) <= 0) {
			Ensure.that(true).isTrue("00000002");
		}
		MemberGoldBean memberGoldBean = findByMemberId(memberId);
		if (null == memberGoldBean || StringUtils.isBlank(memberGoldBean.getMemberId())) {
			error("找不到会员，memberId = " + memberId);
			return;
		}

		// 1、获取分布式锁，防止重复支付 ====================================================
		String key = "MemberGoldServiceImpl:freezeAmount:" + memberId;

		if (!redisGlobalLock.tryLock(key)) {
			return;
		}
		try {
			// 1、计算冻结资产 ================================================================
			// 转入资产=本+息
			BigDecimal allAmount = amount.add(incomeAmount);
			// 累计购买克重（未到期） += 购买克重
			memberGoldBean.setFreezeBuyAmount(memberGoldBean.getFreezeBuyAmount().add(amount));
			// 总收益 += 预期收益
			memberGoldBean.setFreezeIncomeAmount(memberGoldBean.getFreezeIncomeAmount().add(incomeAmount));
			// 累计收益 += 预期收益 // 20180402日确定收益发放后再累加
			//memberGoldBean.setFreezeIncomeTotalAmount(memberGoldBean.getFreezeIncomeTotalAmount().add(incomeAmount));
			// 冻结资产 = （购买克重 + 总收益）
			memberGoldBean.setFreezeAmount(BigDecimalUtil.adds(memberGoldBean.getFreezeBuyAmount(), memberGoldBean.getFreezeIncomeAmount()));

			// 2、计算总资产 ================================================================
			// 总资产 = 可用资产 + 冻结资产
			memberGoldBean.setTotalAmount(BigDecimalUtil.adds(memberGoldBean.getUsableAmount(), memberGoldBean.getFreezeAmount()));

			// 4、修改【资产总表】 ===========================================================
			String[] ids = {memberGoldBean.getId()};
			int rows = memberGoldMapper.updateByPrimaryKeySelective(
					getParams()
							.put("id", ids)
							.put("freezeAmount", memberGoldBean.getFreezeAmount())
							.put("freezeBuyAmount", memberGoldBean.getFreezeBuyAmount())
							.put("freezeIncomeAmount", memberGoldBean.getFreezeIncomeAmount())
							.put("freezeIncomeTotalAmount", memberGoldBean.getFreezeIncomeTotalAmount())
							.put("totalAmount", memberGoldBean.getTotalAmount())
							.toMap());

			Ensure.that(rows).isLt(1, "17000702");
		} catch (Exception e) {
			error(e);
			throw e;
		} finally {
			redisGlobalLock.unlock(key);
		}
	}

	@Override
	@RemoveCache(cleanAll = true)
	public void unfreezeAmount (String memberId, BigDecimal amount, BigDecimal incomeAmount, BillGoldTradeType
	tradeType, BigDecimal goldPrice){
		info("unfreezeAmount memberId = [" + memberId + "], amount = [" + amount + "], incomeAmount = [" + incomeAmount + "]");
		if (StringUtils.isBlank(memberId)) {
			return;
		}
		if (BigDecimalUtil.isZeroOrNull(amount) || BigDecimalUtil.isZeroOrNull(incomeAmount) ||
				amount.compareTo(BigDecimal.ZERO) <= 0 || incomeAmount.compareTo(BigDecimal.ZERO) <= 0) {
			Ensure.that(true).isTrue("00000002");
		}
		MemberGoldBean memberGoldBean = findByMemberId(memberId);
		if (null == memberGoldBean || StringUtils.isBlank(memberGoldBean.getMemberId())) {
			error("找不到会员，memberId = " + memberId);
			return;
		}
		// 1、获取分布式锁，防止重复支付 ====================================================
		String key = "MemberGoldServiceImpl:unfreezeAmount:" + memberId;

		if (!redisGlobalLock.tryLock(key)) {
			return;
		}
		try {
			// 1、计算冻结资产 ================================================================
			// 转入资产=本+息
			BigDecimal allAmount = amount.add(incomeAmount);
			// 累计购买克重（未到期） -= 购买克重
			memberGoldBean.setFreezeBuyAmount(memberGoldBean.getFreezeBuyAmount().subtract(amount));
			// 总收益 -= 预期收益
			memberGoldBean.setFreezeIncomeAmount(memberGoldBean.getFreezeIncomeAmount().subtract(incomeAmount));
			// 冻结资产 = （购买克重 + 总收益）
			memberGoldBean.setFreezeAmount(BigDecimalUtil.adds(memberGoldBean.getFreezeBuyAmount(), memberGoldBean.getFreezeIncomeAmount()));
			// 累计收益 += 预期收益 // 20180402日确定收益发放后再累加
			memberGoldBean.setFreezeIncomeTotalAmount(memberGoldBean.getFreezeIncomeTotalAmount().add(incomeAmount));

			// 2、计算T日本金 ================================================================
			// T日本金 += 转入资产
			memberGoldBean.setPrincipalNowAmount(BigDecimalUtil.add(memberGoldBean.getPrincipalNowAmount(), allAmount));
			// 本金 = T日本金 + (T-1日本金)
			memberGoldBean.setPrincipalAmount(BigDecimalUtil.adds(memberGoldBean.getPrincipalNowAmount(), memberGoldBean.getPrincipalHistoryAmount()));
			// 可用资产 = 本金 + 活期利息
			memberGoldBean.setUsableAmount(BigDecimalUtil.adds(memberGoldBean.getPrincipalAmount(), memberGoldBean.getInterestAmount()));

			// 3、计算转入总资产 =============================================================
			// 转入总资产 += 转入资产
			memberGoldBean.setTurnIntoAmount(BigDecimalUtil.add(memberGoldBean.getTurnIntoAmount(), allAmount));

			// 4、修改【资产总表】 ===========================================================
			String[] ids = {memberGoldBean.getId()};
			int rows = memberGoldMapper.updateByPrimaryKeySelective(
					getParams()
							.put("id", ids)
							.put("freezeAmount", memberGoldBean.getFreezeAmount())
							.put("freezeBuyAmount", memberGoldBean.getFreezeBuyAmount())
							.put("freezeIncomeAmount", memberGoldBean.getFreezeIncomeAmount())
							.put("freezeIncomeTotalAmount", memberGoldBean.getFreezeIncomeTotalAmount())
							.put("principalNowAmount", memberGoldBean.getPrincipalNowAmount())
							.put("principalAmount", memberGoldBean.getPrincipalAmount())
							.put("usableAmount", memberGoldBean.getUsableAmount())
							.put("turnIntoAmount", memberGoldBean.getTurnIntoAmount())
							.toMap());

			Ensure.that(rows).isLt(1, "17000702");

			// 5、增加资产转入转出记录 =====================================================
			BillGoldBean billGoldBean = new BillGoldBean();
			billGoldBean.setMemberId(memberId);
			// 转入资产 = 购买克重 + 预期收益
			billGoldBean.setAmount(BigDecimalUtil.add(amount, incomeAmount));
			// 手续费
			billGoldBean.setFee(BigDecimal.ZERO);
			// 实际资产(资产-手续费)
			billGoldBean.setActualAmount(BigDecimalUtil.subtract(billGoldBean.getAmount(), billGoldBean.getFee()));
			// 金价
			billGoldBean.setGoldPrice(goldPrice);
			billGoldBean.setType(BillGoldType.INCOME.getValue());
			billGoldBean.setTradeType(tradeType.getValue());
			billGoldService.save(billGoldBean);
		} catch (Exception e) {
			error(e);
			throw e;
		} finally {
			redisGlobalLock.unlock(key);
		}
	}

	@Override
	public BigDecimal viewUsableAmount (String memberId){
		if (StringUtils.isBlank(memberId)) {
			return null;
		}
		MemberGoldBean memberGoldBean = findByMemberId(memberId);
		if (null == memberGoldBean || StringUtils.isBlank(memberGoldBean.getMemberId())) {
			error("找不到会员，memberId = " + memberId);
			return null;
		}

		// 可用资产 = (T-1日利息) + T日本金 + (T-1日本金)
		BigDecimal usableAmount = BigDecimalUtil.adds(memberGoldBean.getInterestHistoryAmount(), memberGoldBean.getPrincipalNowAmount(), memberGoldBean.getPrincipalHistoryAmount());
		return BigDecimalUtil.to5Point(usableAmount);
	}

	@Override
	public boolean tryPayAmount (String memberId, BigDecimal amount){
		if (StringUtils.isBlank(memberId)) {
			return false;
		}
		if (BigDecimalUtil.isZeroOrNull(amount) || amount.compareTo(BigDecimal.ZERO) <= 0) {
			Ensure.that(true).isTrue("00000002");
		}
		MemberGoldBean memberGoldBean = findByMemberId(memberId);
		if (null == memberGoldBean || StringUtils.isBlank(memberGoldBean.getMemberId())) {
			error("找不到会员，memberId = " + memberId);
			return false;
		}

		// 可用资产 = (T-1日利息) + T日本金 + (T-1日本金)
		BigDecimal usableAmount = BigDecimalUtil.adds(memberGoldBean.getInterestHistoryAmount(), memberGoldBean.getPrincipalNowAmount(), memberGoldBean.getPrincipalHistoryAmount());

		if (usableAmount.compareTo(amount) >= 0) {
			return true;
		}

		return false;
	}

	@Override
	public BigDecimal[] payAmount (String memberId, BigDecimal amount, BillGoldTradeType tradeType, BigDecimal
	goldPrice, BigDecimal feeFactor){
		info("payAmount memberId = [" + memberId + "], amount = [" + amount + "], tradeType = [" + tradeType + "]");
		if (StringUtils.isBlank(memberId)) {
			return null;
		}

		if (BigDecimalUtil.isZeroOrNull(amount) || amount.compareTo(BigDecimal.ZERO) <= 0) {
			Ensure.that(true).isTrue("00000002");
		}

		// 1、获取分布式锁，防止重复支付 ====================================================
		String key = "MemberGoldServiceImpl:payAmount:" + memberId;

		if (!redisGlobalLock.lock(key)) {
			return null;
		}
		try {
			// 2、获取会员资产可用余额，校验是否可以支付 ======================================
			if (!tryPayAmount(memberId, amount)) {
				return null;
			}
			MemberGoldBean memberGoldBean = findByMemberId(memberId);

			// {支付总金额、T-1日利息、T日本金、T-1日本金}
			BigDecimal[] payAmount = new BigDecimal[4];
			payAmount[0] = amount;
			payAmount[1] = BigDecimal.ZERO;
			payAmount[2] = BigDecimal.ZERO;
			payAmount[3] = BigDecimal.ZERO;

			// 3、扣除 T-1日利息 ===========================================================
			if (amount.compareTo(BigDecimal.ZERO) > 0) {
				BigDecimal interestHistoryAmount = memberGoldBean.getInterestHistoryAmount();
				if (interestHistoryAmount.compareTo(amount) >= 0) {
					interestHistoryAmount = BigDecimalUtil.subtract(interestHistoryAmount, amount);
					memberGoldBean.setInterestHistoryAmount(interestHistoryAmount);
					payAmount[1] = amount;

					amount = BigDecimal.ZERO;
				} else {
					memberGoldBean.setInterestHistoryAmount(BigDecimal.ZERO);
					payAmount[1] = interestHistoryAmount;

					amount = BigDecimalUtil.subtract(amount, interestHistoryAmount);
				}
			}

			// 4、扣除 T日本金 =============================================================
			if (amount.compareTo(BigDecimal.ZERO) > 0) {
				BigDecimal principalNowAmount = memberGoldBean.getPrincipalNowAmount();
				if (principalNowAmount.compareTo(amount) >= 0) {
					principalNowAmount = BigDecimalUtil.subtract(principalNowAmount, amount);
					memberGoldBean.setPrincipalNowAmount(principalNowAmount);
					payAmount[2] = amount;

					amount = BigDecimal.ZERO;
				} else {
					memberGoldBean.setPrincipalNowAmount(BigDecimal.ZERO);
					payAmount[2] = principalNowAmount;

					amount = BigDecimalUtil.subtract(amount, principalNowAmount);
				}
			}

			// 5、扣除 T-1日本金 ===========================================================
			if (amount.compareTo(BigDecimal.ZERO) > 0) {
				BigDecimal principalHistoryAmount = memberGoldBean.getPrincipalHistoryAmount();
				if (principalHistoryAmount.compareTo(amount) >= 0) {
					principalHistoryAmount = BigDecimalUtil.subtract(principalHistoryAmount, amount);
					memberGoldBean.setPrincipalHistoryAmount(principalHistoryAmount);
					payAmount[3] = amount;

					amount = BigDecimal.ZERO;
				} else {
					memberGoldBean.setPrincipalHistoryAmount(BigDecimal.ZERO);
					payAmount[3] = principalHistoryAmount;

					amount = BigDecimalUtil.subtract(amount, principalHistoryAmount);
				}
			}
			if (!BigDecimalUtil.isZeroOrNull(amount)) {
				// 如果余额不足以支付
				return null;
			}

			// 6、资产表中其他变动 ===========================================================
			// 活期利息 = T日利息 + (T-1日利息)
//			memberGoldBean.setInterestAmount(BigDecimalUtil.adds(memberGoldBean.getInterestNowAmount(), memberGoldBean.getInterestHistoryAmount()));
			// 活期利息 = (T-1日利息)  2018-03-30决定活期利息不包含T日利息。T日利息对用户不可见
			memberGoldBean.setInterestAmount(memberGoldBean.getInterestHistoryAmount());
			// 本金 = T日本金 + (T-1日本金)
			memberGoldBean.setPrincipalAmount(BigDecimalUtil.adds(memberGoldBean.getPrincipalNowAmount(), memberGoldBean.getPrincipalHistoryAmount()));
			// 可用资产 = 本金 + 活期利息
			memberGoldBean.setUsableAmount(BigDecimalUtil.adds(memberGoldBean.getPrincipalAmount(), memberGoldBean.getInterestAmount()));
			// 总资产 = 可用资产 + 冻结资产
			memberGoldBean.setTotalAmount(BigDecimalUtil.adds(memberGoldBean.getUsableAmount(), memberGoldBean.getFreezeAmount()));
			// 转出总资产 += 支付总额
			memberGoldBean.setTurnOutAmount(BigDecimalUtil.adds(memberGoldBean.getTurnOutAmount(), payAmount[0]));

			// 7、修改【资产总表】 ===========================================================
			String[] ids = {memberGoldBean.getId()};
			int rows = memberGoldMapper.updateByPrimaryKeySelective(
					getParams()
							.put("id", ids)
							.put("interestHistoryAmount", memberGoldBean.getInterestHistoryAmount())
							.put("principalNowAmount", memberGoldBean.getPrincipalNowAmount())
							.put("principalHistoryAmount", memberGoldBean.getPrincipalHistoryAmount())
							.put("interestAmount", memberGoldBean.getInterestAmount())
							.put("principalAmount", memberGoldBean.getPrincipalAmount())
							.put("usableAmount", memberGoldBean.getUsableAmount())
							.put("totalAmount", memberGoldBean.getTotalAmount())
							.put("turnOutAmount", memberGoldBean.getTurnOutAmount())
							.toMap());

			Ensure.that(rows).isLt(1, "17000702");

			// 3、新增资产转出记录【卖金】 ============================================================
			BillGoldBean billGoldBean = new BillGoldBean();
			billGoldBean.setMemberId(memberId);
			// 转出资产
			billGoldBean.setAmount(payAmount[0]);
			// 手续费
			if (feeFactor == null) {
				billGoldBean.setFee(BigDecimal.ZERO);
			} else {
				billGoldBean.setFee(feeFactor);
			}
			// 实际资产(资产-手续费)
			billGoldBean.setActualAmount(billGoldBean.getAmount());
			// 金价
			billGoldBean.setGoldPrice(goldPrice);
			billGoldBean.setType(BillGoldType.OUTLAY.getValue());
			billGoldBean.setTradeType(tradeType.getValue());
			billGoldService.save(billGoldBean);
			return payAmount;
		} catch (Exception e) {
			error("支付失败", e);
			throw e;
		} finally {
			redisGlobalLock.unlock(key);
		}
	}

	@Override
	public SellGoldBean sellGoldCalculate (String memberId, BigDecimal weight){
		if (StringUtils.isBlank(memberId) || BigDecimalUtil.isZeroOrNull(weight)) {
			return null;
		}
		if (weight.doubleValue() <= 0) {
			Ensure.that(true).isTrue("00000002");
		}
		String hashKey = KEY_SELL_GOLD_PRICE + memberId;

		SerializeObject serializeObject = priceService.currentGoldPrice();
		if (null == serializeObject || serializeObject.getCode() != ResultType.NORMAL) {
			Ensure.that(true).isTrue("17000708");
		}

		// 判断有没有超出每人每日最高卖出克重
		String date = UF.getFormatDateNow();
		// 今日已经卖出克重
		BigDecimal sellTotalAmount = billGoldService.totalAmountByTradeType(memberId, BillGoldTradeType.SELL_GOLD.getValue(), date);
		SerializeObject result = rateSettingsService.get(RateKeyEnum.BUY_SELL_GRAM.getKey());
		if (result.getData()!=null) {
			Map<String, Object> map = (Map<String, Object>) result.getData();
			String maxGramPerday = String.valueOf(map.get(SELL_MAX_GRAM_PERDAY));
			if (!"0".equals(maxGramPerday)){
				// 今日可售克重
				sellTotalAmount = BigDecimalUtil.subtract(new BigDecimal(maxGramPerday), sellTotalAmount);
				if (weight.compareTo(sellTotalAmount) > 0) {
					error("超出每人每日最高卖出克重 memberId = " + memberId);
					Ensure.that(true).isTrue("17000710");
				}
			}
		}

		// 获取实时金价 + 锁定金价
		BigDecimal currentGoldPrice = new BigDecimal(serializeObject.getData().toString());
		cacheUtilsService.setCache(hashKey, currentGoldPrice);
		BigDecimal actualWeight = weight;
		if (BigDecimal.ONE.compareTo(actualWeight) > 0) {
			actualWeight = BigDecimal.ONE;
		}
		// 总价 = 出售金价 * 出售克重
		BigDecimal totalAmount = BigDecimalUtil.multiply(currentGoldPrice, weight);
		BigDecimal fee = BigDecimal.ZERO;
		SerializeObject rateBean  = rateSettingsService.get(RateKeyEnum.SELL_GOLD.getKey());
		if (rateBean != null && rateBean.getData() != null) {
			JSONObject json = JSON.parseObject(JSONObject.toJSONString(rateBean.getData()));
			int dayNum = billMapper.getTransactionNumForThisDay(memberId, 2);
			int monthNum = billMapper.getTransactionNumForThisMonth(memberId, 2);
			fee = fundRateConfig. getSellGoldFee(json, totalAmount, actualWeight, dayNum, monthNum);
		}
		// 实际到账（总价 - 手续费）
		BigDecimal actualAmount = BigDecimalUtil.subtract(totalAmount, fee);
		// 用户卖金费用≤卖金手续费，则卖金费用全部冲抵手续费
		if (fee.compareTo(totalAmount) > 0) {
			fee = totalAmount;
			actualAmount = BigDecimal.ZERO;
		}

		SellGoldBean sellGoldBean = new SellGoldBean();
		sellGoldBean.setMemberId(memberId);
		sellGoldBean.setWeight(weight);
		sellGoldBean.setGoldPrice(currentGoldPrice);
		sellGoldBean.setTotalAmount(totalAmount);
		sellGoldBean.setFee(fee);
		sellGoldBean.setActualAmount(actualAmount);

		return sellGoldBean;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	@RemoveCache(cleanAll = true, cleanService = {BillGoldServiceImpl.class, MemberGoldServiceImpl.class, MemberAccountServiceImpl.class})
	public boolean sellGold (String memberId, BigDecimal weight){
		info("sellGold memberId = [" + memberId + "], weight = [" + weight + "]");
		if (StringUtils.isBlank(memberId) || BigDecimalUtil.isZeroOrNull(weight)) {
			return false;
		}
		if (weight.doubleValue() <= 0) {
			Ensure.that(true).isTrue("00000002");
		}
		// TODO 判断是否终止交易（活期产品如果终止交易，不允许卖金） 20180430 新增限制
		//TODO 新版本提单预留卖金接口
		/*SerializeObject o = productService.findIsSell();
		if (null == o || ResultType.NORMAL != o.getCode()) {
			Ensure.that(true).isTrue(o.getMsg());
		}*/

		// 1、获取分布式锁，防止重复支付 ====================================================
		String key = "MemberGoldServiceImpl:sellGold:" + memberId;

		if (!redisGlobalLock.lock(key)) {
			Ensure.that(true).isTrue("17000706");
			return false;
		}
		try {
			// 判断有没有超出每人每日最高卖出克重
			String date = UF.getFormatDateNow();
			// 今日已经卖出克重
			BigDecimal sellTotalAmount = billGoldService.totalAmountByTradeType(memberId, BillGoldTradeType.SELL_GOLD.getValue(), date);
			SerializeObject result = rateSettingsService.get(RateKeyEnum.BUY_SELL_GRAM.getKey());
			if (result.getData()!=null) {
				Map<String, Object> map = (Map<String, Object>) result.getData();
				String maxGramPerday = String.valueOf(map.get(SELL_MAX_GRAM_PERDAY));
				if (!"0".equals(maxGramPerday)){
					// 今日可售克重
					sellTotalAmount = BigDecimalUtil.subtract(new BigDecimal(maxGramPerday), sellTotalAmount);
					if (weight.compareTo(sellTotalAmount) > 0) {
						error("超出每人每日最高卖出克重 memberId = " + memberId);
						Ensure.that(true).isTrue("17000710");
					}
				}
			}

			// 出售金价
			String hashKey = KEY_SELL_GOLD_PRICE + memberId;
			Object cacheGoldPrice = cacheUtilsService.getCache(hashKey);
			if (null == cacheGoldPrice) {
				Ensure.that(true).isTrue("17000709");
			}
			BigDecimal currentGoldPrice = new BigDecimal(cacheGoldPrice.toString());

			// 不足1克，按1克计算
			BigDecimal calculateWeight = weight;
			if (BigDecimal.ONE.compareTo(calculateWeight) > 0) {
				calculateWeight = BigDecimal.ONE;
			}
			// 总价 = 出售金价 * 出售克重
			BigDecimal totalAmount = BigDecimalUtil.multiply(currentGoldPrice, weight);
			BigDecimal fee = BigDecimal.ZERO;
			SerializeObject rateBean  = rateSettingsService.get(RateKeyEnum.SELL_GOLD.getKey());
			if (rateBean != null && rateBean.getData() != null) {
				JSONObject json = JSON.parseObject(JSONObject.toJSONString(rateBean.getData()));
				int dayNum = billMapper.getTransactionNumForThisDay(memberId, 2);
				int monthNum = billMapper.getTransactionNumForThisMonth(memberId, 2);
				fee = fundRateConfig. getSellGoldFee(json, totalAmount, calculateWeight, dayNum, monthNum);
			}
			BigDecimal feeFactor = BigDecimalUtil.to2Point(fee.divide(calculateWeight, 10, ROUND_HALF_UP));

			BigDecimal[] payAmount = payAmount(memberId, weight, BillGoldTradeType.SELL_GOLD, currentGoldPrice, feeFactor);
			if (null == payAmount) {
				error("可用资产不足 memberId = " + memberId);
				Ensure.that(true).isTrue("17000707");
			}

			// 4、计算手续费和价格 ============================================================

			// 实际到账（总价 - 手续费）
			BigDecimal actualAmount = BigDecimalUtil.subtract(totalAmount, fee);
			// 用户卖金费用≤卖金手续费，则卖金费用全部冲抵手续费
			if (fee.compareTo(totalAmount) > 0) {
				fee = totalAmount;
				actualAmount = BigDecimal.ZERO;
			}

			// 实际到账金额充入用户资金余额（暂缺）
			memberAccountService.sellGold(memberId, totalAmount, fee, currentGoldPrice, weight);

			// 移除缓存的金价
			cacheUtilsService.deleteCache(hashKey);

			// 触发消息
			msgBySellGold(memberId, weight, actualAmount, currentGoldPrice, fee);
			return true;
		} catch (Exception e) {
			error("卖金失败", e);
			return false;
		} finally {
			redisGlobalLock.unlock(key);
		}
	}

	@Override
	public DataTable<MemberGoldGroupByDayBean> queryGroupByDay ( int pageNum, int pageSize, String memberId){
		Page<MemberGoldGroupByDayBean> page = PageHelper.startPage(pageNum, pageSize);
		List<MemberGoldGroupByDayBean> dataList = new ArrayList<>();
		List<MemberGold> list = memberGoldMapper.queryGroupByDay(memberId);
		for (MemberGold o : list) {
			MemberGoldGroupByDayBean objBean = dozerBeanMapper.map(o, MemberGoldGroupByDayBean.class);
			objBean.setAddTimeString(UF.getFormatDate(o.getAddTime()));
			dataList.add(objBean);
		}

		return new DataTable<>(page.getPageNum(), page.getPageSize(), page.getTotal(), dataList);
	}

	@Override
	public PayGoldStock selectEverydayTotalGramRecord () {
		return memberGoldMapper.selectEverydayTotalGramRecord();
	}

	/**
	 * 卖金消息提醒
	 * @param memberId        会员ID
	 * @param reduceGram    产品量减少克重
	 * @param changeAmount    账户增加金额
	 * @param currentGoldPrice    卖时金价
	 * @param fee                手续费
	 */
	private void msgBySellGold (String memberId, BigDecimal reduceGram, BigDecimal changeAmount, BigDecimal
	currentGoldPrice, BigDecimal fee){
		info("msgBySellGold memberId = [" + memberId + "], reduceGram = [" + reduceGram + "], changeAmount = [" + changeAmount + "]");
		MemberGoldBean memberGoldBean = findByMemberId(memberId);
		// 可用资产
		BigDecimal usableAmount = memberGoldBean.getUsableAmount();

		Msg msg = new Msg();
		msg.setMemberId(memberId);
		msg.setType(CommonConstants.MsgType.SELL_GOLD.getIndex());

		Map<String, String> paramMap = new HashMap<>();
		paramMap.put("reduceGram", BigDecimalUtil.to5Point(reduceGram).toString());
		paramMap.put("gram", BigDecimalUtil.to5Point(usableAmount).toString());
		msg.setParamMap(paramMap);

		amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);

		// 账户变动提醒(收入)
	/*usableAmount = memberAccountService.queryUsableAmount();
	msg.setType(CommonConstants.MsgType.ACCOUNT_INCOME_CHANGE.getIndex());
	paramMap.clear();
	paramMap.put("date", UF.getFormatDate("MM月dd日", UF.getDateTime()));
	paramMap.put("changeAmount", BigDecimalUtil.to2Point(changeAmount).toString());
	paramMap.put("amount", BigDecimalUtil.to2Point(usableAmount).toString());
	msg.setParamMap(paramMap);

	amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);*/


		/**
		 * 微信服务号消息推送  定期产品到期后
		 */
	/*WxMessageParamBean wxMessageParamBean = new WxMessageParamBean();
	wxMessageParamBean.setMemberId(memberId);
	//消息推送类型
	wxMessageParamBean.setType(WxTemplateEnum.sale_gold_SUCCEED.getType());
	WxTemplateEnum wxTemplateEnum = WxTemplateEnum.getWxTemplateByCode(WxTemplateEnum.sale_gold_SUCCEED.getType());
	WxNotifyData wxNotifyData = new WxNotifyData();

	Map<String, WxNotifyData.TemplateDataAttr> wxParamMap = new HashMap();
	WxNotifyData.TemplateDataAttr first = new WxNotifyData.TemplateDataAttr();
	first.setDataValue(wxTemplateEnum.getFirstData().replace("{weight}", BigDecimalUtil.to5Point(reduceGram).toString()).
			replace("{balance}", BigDecimalUtil.to5Point(usableAmount).toString()).replace("{money}", BigDecimalUtil.to2Point(changeAmount).toString()));
	wxParamMap.put("first", first);

	WxNotifyData.TemplateDataAttr keyword1 = new WxNotifyData.TemplateDataAttr();
	keyword1.setDataValue(BigDecimalUtil.to2Point(changeAmount).toString());
	wxParamMap.put("keyword1", keyword1);

	WxNotifyData.TemplateDataAttr keyword2 = new WxNotifyData.TemplateDataAttr();
	keyword2.setDataValue(BigDecimalUtil.to5Point(reduceGram).toString());
	wxParamMap.put("keyword2", keyword2);

	WxNotifyData.TemplateDataAttr keyword3 = new WxNotifyData.TemplateDataAttr();
	keyword3.setDataValue(BigDecimalUtil.to2Point(currentGoldPrice).toString());
	wxParamMap.put("keyword3", keyword3);

	WxNotifyData.TemplateDataAttr keyword4 = new WxNotifyData.TemplateDataAttr();
	keyword4.setDataValue(BigDecimalUtil.to2Point(fee).toString());
	wxParamMap.put("keyword4", keyword4);

	WxNotifyData.TemplateDataAttr keyword5 = new WxNotifyData.TemplateDataAttr();
	keyword5.setDataValue(DateUtils.dateToStr(new Date(),DateUtils.patter));
	wxParamMap.put("keyword5", keyword5);

	WxNotifyData.TemplateDataAttr remark = new WxNotifyData.TemplateDataAttr();
	remark.setDataValue(wxTemplateEnum.getRemark());
	wxParamMap.put("remark", remark);

	wxNotifyData.setData(wxParamMap);
	wxMessageParamBean.setTemplateData(wxNotifyData);
	amqpTemplate.convertAndSend(QUEUE_MSG_WX_SEND, wxMessageParamBean);*/
	}

	/**
	 * 获取数据列表
	 * @param order            排序字段
	 * @param sort            排序方式 desc或asc
	 * @param amountMin        最小黄金总资产
	 * @param amountMax        最大黄金总资产
	 * @param usableAmountMin    最小可用资产
	 * @param usableAmountMax    最大可用资产
	 * @param freezeAmountMin    最小冻结资产
	 * @param freezeAmountMax    最大冻结资产
	 * @param turnIntoAmountMin    最小转入资产
	 * @param turnIntoAmountMax    最大转入资产
	 * @param turnOutAmountMin    最小转出资产
	 * @param turnOutAmountMax    最大转出资产
	 * @param addTimeMin    最小创建时间
	 * @param addTimeMax    最大创建时间
	 * @param memberId        会员ID
	 * @param memberName    会员名称
	 * @param memberMobile    会员手机
	 * @param keyword        关键字
	 * @return 列表
	 */
	private List<MemberGoldBean> query (String order, String sort,
			BigDecimal amountMin, BigDecimal amountMax,
			BigDecimal usableAmountMin, BigDecimal usableAmountMax,
			BigDecimal freezeAmountMin, BigDecimal freezeAmountMax,
			BigDecimal turnIntoAmountMin, BigDecimal turnIntoAmountMax,
			BigDecimal turnOutAmountMin, BigDecimal turnOutAmountMax,
			LocalDateTime addTimeMin, LocalDateTime addTimeMax,
			String memberId, String memberName, String memberMobile, String keyword){
		if (null != addTimeMax) {
			// 加一天减一秒
			addTimeMax = addTimeMax.plusDays(1).minusSeconds(1);
		}
		List<MemberGoldBean> dataList = new ArrayList<>();
		List<MemberGold> list = memberGoldMapper.query(
				getParams(keyword, order, sort)
						.put("amountMin", amountMin)
						.put("amountMax", amountMax)
						.put("usableAmountMin", usableAmountMin)
						.put("usableAmountMax", usableAmountMax)
						.put("freezeAmountMin", freezeAmountMin)
						.put("freezeAmountMax", freezeAmountMax)
						.put("turnIntoAmountMin", turnIntoAmountMin)
						.put("turnIntoAmountMax", turnIntoAmountMax)
						.put("turnOutAmountMin", turnOutAmountMin)
						.put("turnOutAmountMax", turnOutAmountMax)
						.put("addTimeMin", addTimeMin)
						.put("addTimeMax", addTimeMax)
						.put("memberId", memberId)
						.put("memberName", UF.escapeSql(memberName))
						.put("memberMobile", UF.escapeSql(memberMobile))
						.toMap());
		for (MemberGold o : list) {
			MemberGoldBean objBean = dozerBeanMapper.map(o, MemberGoldBean.class);
			objBean.setAddTimeString(UF.getFormatDateTime(o.getAddTime()));
			objBean.setModifyTimeString(UF.getFormatDateTime(o.getModifyTime()));
			dataList.add(objBean);
		}
		return dataList;
	}

	/**
	 * 查询有效账户
	 * @return 当前页记录数
	 */
	private List<MemberGoldBean> queryActiveAccount () {
		List<MemberGoldBean> dataList = new ArrayList<>();
		List<MemberGold> list = memberGoldMapper.queryActiveAccount();
		for (MemberGold o : list) {
			MemberGoldBean objBean = dozerBeanMapper.map(o, MemberGoldBean.class);
			objBean.setAddTimeString(UF.getFormatDateTime(o.getAddTime()));
			objBean.setModifyTimeString(UF.getFormatDateTime(o.getModifyTime()));
			dataList.add(objBean);
		}
		return dataList;
	}

	@Override
	public List<MemberGoldBeanBean> queryForBean(String name, String mobile, int beanFrom, int beanTo, String startDate, String endDate, String order, String sort, int offset, int size) {
		Map<String, Object> params = new HashMap<String, Object>();
		if (StringUtils.isNotBlank(name)) {
			params.put("name", name);
		}
		if (StringUtils.isNotBlank(mobile)) {
			params.put("mobile", mobile);
		}
		params.put("beanFrom", beanFrom);
		params.put("beanTo", beanTo);
		if (StringUtils.isNotBlank(startDate)) {
			params.put("startDate", startDate);
		}
		if (StringUtils.isNotBlank(endDate)) {
			params.put("endDate", endDate);
		}
		List<String> orders = Arrays.asList("totalBean", "usableBean", "freezeBean");
		if (orders.contains(order)) {
			params.put("order", order);
			params.put("sort", "desc");
			if (StringUtils.equalsIgnoreCase(sort, "asc") || StringUtils.equalsIgnoreCase(sort, "desc")) {
				params.put("sort", sort);
			}
		}
		params.put("offset", offset);
		params.put("size", size);
		return memberGoldMapper.queryForBean(params);
	}

	@Override
	public int countForBean(String name, String mobile, int beanFrom, int beanTo, String startDate, String endDate) {
		Map<String, Object> params = new HashMap<String, Object>();
		if (StringUtils.isNotBlank(name)) {
			params.put("name", name);
		}
		if (StringUtils.isNotBlank(mobile)) {
			params.put("mobile", mobile);
		}
		params.put("beanFrom", beanFrom);
		params.put("beanTo", beanTo);
		if (StringUtils.isNotBlank(startDate)) {
			params.put("startDate", startDate);
		}
		if (StringUtils.isNotBlank(endDate)) {
			params.put("endDate", endDate);
		}

		return memberGoldMapper.countForBean(params);
	}
}

